﻿namespace Microsoft.SharePoint.Client
{
    using System;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;

    public abstract class ClientObject : IFromJson
    {
        private ClientRuntimeContext m_context;
        private ClientObjectData m_objectData;
        private ClientObjectCollection m_parentCollection;
        private bool m_setAsNull;

        [EditorBrowsable(EditorBrowsableState.Never)]
        protected ClientObject(ClientRuntimeContext context, ObjectPath objectPath)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            this.m_context = context;
            this.m_objectData = new ClientObjectData();
            this.m_objectData.Path = objectPath;
        }

        protected void CheckUninitializedProperty(string propName)
        {
            if (!this.m_objectData.Properties.ContainsKey(propName))
            {
                throw new PropertyOrFieldNotInitializedException();
            }
        }

        internal virtual void CleanupQuery()
        {
            this.m_objectData.Query = null;
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        public virtual bool CustomFromJson(JsonReader reader)
        {
            return false;
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        public virtual void FromJson(JsonReader reader)
        {
            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }
            if (reader.PeekTokenType() == JsonTokenType.Null)
            {
                this.SetAsNull();
                reader.ReadObject();
            }
            else
            {
                reader.ReadObjectStart();
                while (reader.PeekTokenType() != JsonTokenType.ObjectEnd)
                {
                    string peekedName = reader.PeekName();
                    if (!this.InitOnePropertyFromJson(peekedName, reader))
                    {
                        if (peekedName == "_ObjectType_")
                        {
                            reader.ReadName();
                            reader.ReadObject();
                        }
                        else
                        {
                            if (peekedName == "_ObjectIdentity_")
                            {
                                reader.ReadName();
                                string identity = reader.ReadString();
                                ObjectPath path = new ObjectPathIdentity(this.Context, identity);
                                if (this.m_objectData.Path != null)
                                {
                                    path.Id = this.m_objectData.Path.Id;
                                }
                                this.m_objectData.Path = path;
                                path.ServerObjectIsNull = false;
                                this.Context.AddObjectPath(path);
                                continue;
                            }
                            if (peekedName == "_ObjectVersion_")
                            {
                                reader.ReadName();
                                string str3 = reader.ReadString();
                                this.m_objectData.Version = str3;
                            }
                            else
                            {
                                this.InitNonPropertyFieldFromJson(peekedName, reader);
                            }
                        }
                    }
                }
                reader.ReadObjectEnd();
            }
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        protected virtual void InitNonPropertyFieldFromJson(string peekedName, JsonReader reader)
        {
            reader.ReadName();
            reader.ReadObject();
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        protected virtual bool InitOnePropertyFromJson(string peekedName, JsonReader reader)
        {
            return false;
        }

        public bool IsObjectPropertyInstantiated(string propertyName)
        {
            return this.m_objectData.ClientObjectProperties.ContainsKey(propertyName);
        }

        public bool IsPropertyAvailable(string propertyName)
        {
            return this.m_objectData.Properties.ContainsKey(propertyName);
        }

        protected virtual void LoadExpandoFields()
        {
        }

        public virtual void RefreshLoad()
        {
            ClientQueryInternal query = this.Query;
            this.SelectExistingScalarProperties(query);
        }

        protected void RemoveFromParentCollection()
        {
            if (this.m_parentCollection != null)
            {
                this.m_parentCollection.RemoveChild(this);
            }
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        public void Retrieve()
        {
            this.Query.SelectAllProperties();
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        public void Retrieve(params string[] propertyNames)
        {
            ClientQueryInternal query = this.Query;
            if (propertyNames != null)
            {
                foreach (string str in propertyNames)
                {
                    query.Select(str);
                }
            }
        }

        private void SelectExistingScalarProperties(ClientQueryInternal query)
        {
            foreach (string str in this.m_objectData.Properties.Keys)
            {
                query.Select(str);
            }
        }

        internal void SetAsNull()
        {
            this.m_setAsNull = true;
        }

        internal void SetObjectDataFrom(ClientObject otherObject)
        {
            this.m_objectData = otherObject.m_objectData;
        }

        public ClientRuntimeContext Context
        {
            get
            {
                return this.m_context;
            }
        }

        protected internal ClientObjectData ObjectData
        {
            get
            {
                return this.m_objectData;
            }
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        public string ObjectVersion
        {
            get
            {
                return this.m_objectData.Version;
            }
            set
            {
                this.m_objectData.Version = value;
            }
        }

        internal ClientObjectCollection ParentCollection
        {
            get
            {
                return this.m_parentCollection;
            }
            set
            {
                this.m_parentCollection = value;
            }
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        public ObjectPath Path
        {
            get
            {
                return this.m_objectData.Path;
            }
        }

        internal ClientQueryInternal Query
        {
            get
            {
                ClientQueryInternal query = this.m_objectData.Query;
                if ((query == null) || (query != this.Context.PendingRequest.LastAction))
                {
                    query = new ClientQueryInternal(this, null, false, null);
                    this.m_objectData.Query = query;
                    this.Context.AddQueryIdAndResultObject(query.Id, this);
                    this.Context.AddQuery(query);
                    this.Context.AddObjectToQueryCleanupList(this);
                    this.SelectExistingScalarProperties(query);
                    this.LoadExpandoFields();
                }
                return query;
            }
        }

        [PseudoRemote]
        public bool? ServerObjectIsNull
        {
            get
            {
                if (this.m_setAsNull)
                {
                    return true;
                }
                ObjectPath path = this.Path;
                if (path == null)
                {
                    return false;
                }
                return path.ServerObjectIsNull;
            }
        }

        public object Tag { get; set; }
    }
}

